# -*- coding: utf-8 -*-
# @version        : 1.0
# @Creaet Time    : 2021/10/19 15:47
# @File           : case08.py
# @IDE            : PyCharm
# @desc           : 案例08，后台任务


"""
您可以定义要在返回响应后运行的后台任务。

这对于在请求之后需要进行的操作很有用，但是客户端实际上并不需要在收到响应之前就等待操作完成。

这包括，例如：
- 执行操作后发送的电子邮件通知：
    由于连接到电子邮件服务器并发送电子邮件的过程通常很慢（几秒钟），因此您可以立即返回响应并在后台发送电子邮件通知。

- 处理数据：
    例如，假设您收到的文件必须经过缓慢的处理，您可以返回『已接受』（HTTP 202）响应，并在后台对其进行处理。
"""
from typing import Optional
from fastapi import APIRouter, BackgroundTasks, Depends

case08 = APIRouter()


@case08.get("/", summary="案例8初始接口")
def case08_root():
    return "case08_root"


def write_notification(email: str, message=""):
    with open("logs/notification.txt", mode="a") as email_file:
        content = f"发送通知到 {email}: {message}\n"
        email_file.write(content)


"""首先，导入 BackgroundTasks 并在路径操作函数中定义一个带有 BackgroundTasks 类型声明的参数"""
@case08.post("/send-notification/{email}", summary="后台任务")
async def send_notification(email: str, background_tasks: BackgroundTasks):
    """在您的路径操作函数内部，使用 .add_task() 方法将您的任务函数传递给后台对象："""
    background_tasks.add_task(write_notification, email, message="发送内容")
    return {"message": "正在后台发送通知"}


# ====================================依赖注入=========================================================================


"""
使用 BackgroundTasks 还可以与依赖项注入系统一起使用，您可以在多个级别上声明 BackgroundTasks 类型的参数：
- 在路径操作函数中
- 在依赖项中（被依赖项）
- 在子依赖项中
- 等等。

FastAPI 知道每种情况下的操作以及如何重用同一对象，以便所有后台任务合并在一起并在后台运行

如果您需要执行大量的后台计算，而不必一定要在同一进程中运行它（例如，您不需要共享内存，变量等），则可能会受益于使用其他更大的工具，例如 Celery。
它们往往需要更复杂的配置，例如 RabbitMQ 或 Redis 之类的消息/作业队列管理器，但是它们允许您在多个进程（尤其是多个服务器）中运行后台任务。
但是，如果您需要从同一个 FastAPI 应用程序访问变量和对象，或者需要执行一些小的后台任务（例如发送电子邮件通知），则只需使用 BackgroundTasks 即可。
"""


def write_log(message: str):
    with open("logs/log.txt", mode="a") as log:
        log.write(message)


def get_query(background_tasks: BackgroundTasks, desc: Optional[str] = None):
    if desc:
        desc = f"具体描述: {desc}\n"
        background_tasks.add_task(write_log, desc)
    return desc


@case08.get("/send-notification/{email}", summary="后台任务，依赖注入")
async def send_notification(email: str, background_tasks: BackgroundTasks, q: str = Depends(get_query)):
    message = f"发送消息给 {email}\n"
    background_tasks.add_task(write_log, message)
    return {"message": "消息正在发送中"}